#include "EvaluatorDataReaderBase.h"

static bool isLeapYear(int year)
{
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}

static int daysInMonth(int year, int month)
{
    if (month == 2) {
        return isLeapYear(year) ? 29 : 28;
    }
    else if (month == 4 || month == 6 || month == 9 || month == 11) {
        return 30;
    }
    else {
        return 31;
    }
}

static std::vector<algobase::Date> getDatesByYear(const algobase::Date& start, const algobase::Date& end)
{
    std::vector<algobase::Date> result;

    algobase::Date currentDate(start.mYear, 0, 0);
    while (!(end < currentDate)) {
        result.push_back(currentDate);
        currentDate.mYear++;
    }
    return result;
}

static std::vector<algobase::Date> getDatesByMonth(const algobase::Date& start, const algobase::Date& end)
{
    std::vector<algobase::Date> result;

    algobase::Date currentDate(start.mYear, start.mMonth, 0);
    while (!(end < currentDate)) {
        result.push_back(currentDate);
        currentDate.mMonth++;
        if (currentDate.mMonth > 12) {
            currentDate.mMonth = 1;
            currentDate.mYear++;
        }
    }
    return result;
}

std::vector<algobase::Date> getDatesByDay(const algobase::Date& start, const algobase::Date& end)
{
    std::vector<algobase::Date> result;
    algobase::Date currentDate(start.mYear, start.mMonth, start.mDay, 0);

    while (!(end < currentDate)) {
        result.push_back(currentDate);
        currentDate.mDay++;
        if (currentDate.mDay > daysInMonth(currentDate.mYear, currentDate.mMonth)) {
            currentDate.mDay = 1;
            currentDate.mMonth++;
            if (currentDate.mMonth > 12) {
                currentDate.mMonth = 1;
                currentDate.mYear++;
            }
        }
    }
    return result;
}

class reader::EvaEnvDataReaderBasePrivate
{
public:
	reader::EvaEnvDataReaderBase* q = nullptr;
    algobase::TaskConfig mTaskConfig;
};

reader::EvaEnvDataReaderBase::EvaEnvDataReaderBase()
	: d(new EvaEnvDataReaderBasePrivate)
{
	d->q = this;
}

reader::EvaEnvDataReaderBase::~EvaEnvDataReaderBase()
{
	delete d;
}

std::vector<algobase::Date> reader::EvaEnvDataReaderBase::getReadDates() const
{
    switch (d->mTaskConfig.mDateType)
    {
        case algobase::DT_Year:
        {
            return getDatesByYear(d->mTaskConfig.mStartTime, d->mTaskConfig.mEndTime);
        }
        case algobase::DT_Month:
        {
            return getDatesByMonth(d->mTaskConfig.mStartTime, d->mTaskConfig.mEndTime);
        }
        case algobase::DT_Day: 
        {
            return getDatesByDay(d->mTaskConfig.mStartTime, d->mTaskConfig.mEndTime);
        }
        default:
        {
            break;
        }
    }

    return std::vector<algobase::Date>();
}

void reader::EvaEnvDataReaderBase::setTaskConfig(const algobase::TaskConfig& config)
{
    d->mTaskConfig = config;
}

algobase::TaskConfig reader::EvaEnvDataReaderBase::getTaskConfig() const
{
	return d->mTaskConfig;
}
